use tauri::{command, AppHandle, Manager, Runtime};
use tokio::fs::File;
use tokio::io::AsyncReadExt;

#[command]
pub async fn upload_file<R: Runtime>(
    app: AppHandle<R>,
    file_data: Vec<u8>,
    file_name: String,
) -> Result<String, String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    // 创建upload文件夹
    let upload_dir = app_dir.join("upload").join("images");
    if !upload_dir.exists() {
        tokio::fs::create_dir_all(&upload_dir)
            .await
            .map_err(|e| format!("无法创建upload文件夹: {}", e))?;
    }
    
    let file_path = upload_dir.join(&file_name);
    
    tokio::fs::write(&file_path, &file_data)
        .await
        .map_err(|e| e.to_string())?;
    
    Ok(file_name)
}

#[command]
pub async fn get_file_stream<R: Runtime>(
    app: AppHandle<R>,
    file_name: String,
) -> Result<Vec<u8>, String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    let upload_dir = app_dir.join("upload").join("images");
    let file_path = upload_dir.join(&file_name);
    if !file_path.exists() {
        return Err("文件不存在".to_string());
    }
    
    let mut file = File::open(&file_path)
        .await
        .map_err(|e| e.to_string())?;
    
    let mut buffer = Vec::new();
    file.read_to_end(&mut buffer)
        .await
        .map_err(|e| e.to_string())?;
    
    Ok(buffer)
}

#[command]
pub async fn get_file_url<R: Runtime>(
    app: AppHandle<R>,
    file_name: String,
) -> Result<String, String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    let upload_dir = app_dir.join("upload").join("images");
    let file_path = upload_dir.join(&file_name);
    
    if !file_path.exists() {
        return Err("文件不存在".to_string());
    }
    
    // 返回文件路径，前端可以使用URL.createObjectURL或直接使用路径
    Ok(file_path.to_string_lossy().to_string())
}

#[command]
pub async fn list_upload_files<R: Runtime>(
    app: AppHandle<R>,
) -> Result<Vec<String>, String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    let upload_dir = app_dir.join("upload").join("images");
    
    if !upload_dir.exists() {
        return Ok(Vec::new());
    }
    
    let mut entries = tokio::fs::read_dir(&upload_dir)
        .await
        .map_err(|e| e.to_string())?;
    
    let mut file_names = Vec::new();
    while let Some(entry) = entries.next_entry().await.map_err(|e| e.to_string())? {
        if let Ok(file_type) = entry.file_type().await {
            if file_type.is_file() {
                if let Some(file_name) = entry.file_name().to_str() {
                    file_names.push(file_name.to_string());
                }
            }
        }
    }
    
    Ok(file_names)
}

use tauri_plugin_dialog::DialogExt;

#[command]
pub async fn save_file_with_dialog<R: Runtime>(
    app: AppHandle<R>,
    file_data: Vec<u8>,
    default_filename: String,
) -> Result<String, String> {
    // 打开文件保存对话框
    let file_path = tokio::task::spawn_blocking(move || {
        let (tx, rx) = std::sync::mpsc::channel();
        app.dialog()
            .file()
            .set_file_name(&default_filename)
            .save_file(move |result| {
                tx.send(result).unwrap();
            });
        rx.recv().unwrap()
    })
    .await
    .map_err(|e| format!("对话框任务失败: {}", e))?
    .ok_or_else(|| "用户取消了保存".to_string())?;

    // 保存文件到用户选择的位置
    let path = match file_path {
        tauri_plugin_dialog::FilePath::Path(path_buf) => path_buf,
        _ => return Err("无效的文件路径".to_string()),
    };
    tokio::fs::write(&path, &file_data)
        .await
        .map_err(|e| format!("保存文件失败: {}", e))?;

    Ok(path.to_string_lossy().to_string())
}

#[command]
pub async fn save_template_file<R: Runtime>(
    app: AppHandle<R>,
    file_data: Vec<u8>,
) -> Result<String, String> {
    save_file_with_dialog(app, file_data, "患者导入模板.xlsx".to_string()).await
}

use sysinfo::System;
use std::process::Command;

#[command]
pub async fn get_machine_id() -> Result<String, String> {
    // 优先尝试获取BIOS序列号
    let machine_id = if cfg!(target_os = "windows") {
        get_windows_bios_serial().unwrap_or_else(|_| get_fallback_machine_id())
    } else if cfg!(target_os = "linux") {
        get_linux_bios_serial().unwrap_or_else(|_| get_fallback_machine_id())
    } else if cfg!(target_os = "macos") {
        get_macos_bios_serial().unwrap_or_else(|_| get_fallback_machine_id())
    } else {
        get_fallback_machine_id()
    };
    
    Ok(machine_id)
}

// Windows系统获取BIOS序列号
fn get_windows_bios_serial() -> Result<String, String> {
    let output = Command::new("wmic")
        .args(["bios", "get", "serialnumber"])
        .output()
        .map_err(|e| format!("执行wmic命令失败: {}", e))?;
    
    if output.status.success() {
        let result = String::from_utf8_lossy(&output.stdout);
        let lines: Vec<&str> = result.lines().collect();
        if lines.len() >= 2 {
            let serial = lines[1].trim();
            if !serial.is_empty() && serial != "To be filled by O.E.M." {
                return Ok(serial.to_string());
            }
        }
    }
    
    Err("无法获取Windows BIOS序列号".to_string())
}

// Linux系统获取BIOS序列号
fn get_linux_bios_serial() -> Result<String, String> {
    // 尝试使用dmidecode获取BIOS序列号
    let output = Command::new("dmidecode")
        .args(["-s", "system-serial-number"])
        .output();
    
    if let Ok(output) = output {
        if output.status.success() {
            let serial = String::from_utf8_lossy(&output.stdout).trim().to_string();
            if !serial.is_empty() && serial != "Not Specified" {
                return Ok(serial);
            }
        }
    }
    
    // 尝试读取系统机器ID文件作为备选
    if let Ok(content) = std::fs::read_to_string("/etc/machine-id") {
        let machine_id = content.trim();
        if !machine_id.is_empty() {
            return Ok(machine_id.to_string());
        }
    }
    
    Err("无法获取Linux BIOS序列号".to_string())
}

// macOS系统获取BIOS序列号
fn get_macos_bios_serial() -> Result<String, String> {
    let output = Command::new("system_profiler")
        .args(["SPHardwareDataType"])
        .output()
        .map_err(|e| format!("执行system_profiler命令失败: {}", e))?;
    
    if output.status.success() {
        let result = String::from_utf8_lossy(&output.stdout);
        for line in result.lines() {
            if line.contains("Serial Number") {
                if let Some(serial) = line.split(':').nth(1) {
                    let serial = serial.trim();
                    if !serial.is_empty() {
                        return Ok(serial.to_string());
                    }
                }
            }
        }
    }
    
    Err("无法获取macOS BIOS序列号".to_string())
}

// 备用方案：使用系统信息生成机器码
fn get_fallback_machine_id() -> String {
    let mut system = System::new();
    system.refresh_all();
    
    // 获取主机名
    let hostname = System::host_name().unwrap_or_else(|| "unknown-host".to_string());
    
    // 获取CPU信息
    let cpu_info = system.cpus().first().map(|cpu| cpu.brand()).unwrap_or("unknown-cpu");
    
    // 获取内存信息
    let total_memory = system.total_memory();
    
    format!(
        "{:?}-{:?}-{:?}",
        hostname,
        cpu_info,
        total_memory
    )
}

#[command]
pub async fn read_auth_file<R: Runtime>(
    app: AppHandle<R>,
) -> Result<String, String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    let auth_file_path = app_dir.join("auth.txt");
    
    if !auth_file_path.exists() {
        return Ok("".to_string());
    }
    
    let content = tokio::fs::read_to_string(&auth_file_path)
        .await
        .map_err(|e| format!("读取授权文件失败: {}", e))?;
    
    Ok(content)
}

#[command]
pub async fn write_auth_file<R: Runtime>(
    app: AppHandle<R>,
    content: String,
) -> Result<(), String> {
    let app_dir = app.path().app_data_dir()
        .map_err(|_| "无法获取应用数据目录".to_string())?;
    
    // 确保目录存在
    if !app_dir.exists() {
        tokio::fs::create_dir_all(&app_dir)
            .await
            .map_err(|e| format!("创建应用数据目录失败: {}", e))?;
    }
    
    let auth_file_path = app_dir.join("auth.txt");
    
    tokio::fs::write(&auth_file_path, content)
        .await
        .map_err(|e| format!("写入授权文件失败: {}", e))?;
    
    Ok(())
}